package com.avalon.shop.service.wx;

import com.avalon.core.exception.AvalonException;
import com.avalon.core.model.RecordRow;
import com.avalon.core.util.JacksonUtil;
import com.avalon.core.util.RestTemplateUtils;
import com.avalon.core.util.StringUtils;
import com.avalon.shop.model.MediaCheckAsyncResponse;
import com.avalon.shop.model.WXCode2Session;
import com.avalon.shop.model.WxUserPhoneInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WeiXinShopService {
    @Value("${wx.appId:}")
    private String appId;
    @Value("${wx.secret:}")
    private String secret;

    /**
     * 获取微信小程序的openid
     *
     * @param code 临时登录凭证
     * @return
     */
    public WXCode2Session getOpenId(String code) {
        String uri = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret +
                "&js_code=" + code + "&grant_type=authorization_code";
        ResponseEntity<String> wxCode2SessionResponseEntity = RestTemplateUtils.get(uri, String.class);
        WXCode2Session wxCode2Session = JacksonUtil.convert2Object(wxCode2SessionResponseEntity.getBody(), WXCode2Session.class);
        return wxCode2Session;
    }

    /**
     * 获取接口调用凭据
     *
     * @return access_token
     */
    public String getAccessToken() {
        String uri = "https://api.weixin.qq.com/cgi-bin/token?appid=" + appId + "&secret=" + secret + "&grant_type=client_credential";
        ResponseEntity<String> response = RestTemplateUtils.get(uri, String.class);
        if (log.isDebugEnabled()) {
            log.debug("access_token->{}", response.getBody());
        }
        return JacksonUtil.convert2Map(response.getBody()).getString("access_token");
    }

    /**
     * 获取手机号
     *
     * @param code 临时登录凭证
     * @return 手机号
     */
    public WxUserPhoneInfo getUserPhone(String code) {
        String uri = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?appid=" + appId
                + "&access_token=" + getAccess_token();
        Map param = new HashMap<>();
        param.put("code", code);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> response = RestTemplateUtils.post(uri, headers, param, String.class);
        RecordRow result = JacksonUtil.convert2Map(response.getBody());
        Integer errcode = result.getInteger("errcode");
        if (errcode != 0) {
            throw new AvalonException(result.getString("errmsg"));
        }
        return result.getRecordRow("phone_info").convert2Object(WxUserPhoneInfo.class);
    }

    public byte[] getWXACodeUnlimited(String scene, String page) {
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="
                + getAccessToken();
        Map param = new HashMap<>();
        param.put("scene", scene);
        param.put("page", page);
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> response = RestTemplateUtils.post(url, headers, param, String.class);
        if (response.getStatusCode().is2xxSuccessful()) {
            RecordRow recordRow = JacksonUtil.convert2Map(response.getBody());
            if (recordRow.containsKey("errcode") && recordRow.getInteger("errcode") == 0) {
                return (byte[]) recordRow.getRawValue("buffer");
            }
        }
        return null;
    }

    private String access_token;

    @Scheduled(fixedRate = 7200000)
    public void auto_refresh_token() {
        access_token = null; //强制获取最新的access_token
        access_token = getAccessToken();
        log.info("auto_refresh_token run access_token->{}", access_token);
    }

    public String getAccess_token() {
        if (StringUtils.isNotEmpty(access_token)) return access_token;
        auto_refresh_token();
        return access_token;
    }

    /**
     * 文本内容安全识别 用户个人资料违规文字检测  媒体新闻类用户发表文章，评论内容检测
     *
     * @param openId
     * @param content
     * @param scene
     * @return
     */
    public boolean msg_sec_check(String openId, String content, int scene) {
        String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token="
                + getAccess_token();

        Map<String, Object> param = new HashMap();
        param.put("scene", scene);
        param.put("openid", openId);
        param.put("content", content);
        param.put("version", 2);
        if (log.isDebugEnabled()) {
            log.debug("文本内容安全识别,参数->{}", param);
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json;charset=UTF-8");
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<String> response = RestTemplateUtils.post(url, headers, param, String.class);

        if (response.getStatusCode().is2xxSuccessful()) {
            RecordRow recordRow = JacksonUtil.convert2Map(response.getBody());
            if (log.isDebugEnabled()) {
                log.debug("文本内容安全识别,检查结果->{}", response.getBody());
            }
            if (recordRow.containsKey("errcode") && recordRow.getInteger("errcode") == 0) {
                return recordRow.getRecordRow("result").getString("suggest").equals("pass");
            } else if (recordRow.containsKey("errcode") && recordRow.getInteger("errcode") == 40001) {
                // invalid credential, access_token is invalid or not latest
                access_token = getAccessToken();
                return msg_sec_check(openId, content, scene);
            }
        }
        return false;
    }

    /**
     * 检查个人昵称
     *
     * @param openId
     * @param content
     * @return
     */
    public Boolean check_text_user_info(String openId, String content) {
        return msg_sec_check(openId, content, 1);
    }

    /**
     * 评论
     *
     * @param openId
     * @param content
     * @return
     */
    public Boolean check_text_user_comment(String openId, String content) {
        return msg_sec_check(openId, content, 2);
    }

    /**
     * 论坛 发布内容
     */
    public Boolean check_text_forum(String openId, String content) {
        return msg_sec_check(openId, content, 3);
    }

    /**
     * 图片检测
     *
     * @param openId
     * @param image_url
     * @param scene
     * @return
     */
    public MediaCheckAsyncResponse media_check_async(String openId, String image_url, Integer scene) {
        String url = "https://api.weixin.qq.com/wxa/media_check_async?access_token="
                + getAccess_token();
        Map param = new HashMap<>();
        param.put("scene", scene);
        param.put("media_type", 2);
        param.put("media_url", image_url);
        param.put("version", 2);
        param.put("openid", openId);
        if (log.isDebugEnabled()) {
            log.debug("音视频内容安全识别,参数->{}", param);
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("content-type", "application/json");
        headers.put("Accept", MediaType.toString(Arrays.asList(MediaType.APPLICATION_JSON)));
        ResponseEntity<MediaCheckAsyncResponse> response = RestTemplateUtils.post(url, headers, param, MediaCheckAsyncResponse.class);
        if (response.getStatusCode().is2xxSuccessful()) {

            if (log.isDebugEnabled()) {
                log.debug("音视频内容安全识别,检查结果->{}", response.getBody());
            }
            MediaCheckAsyncResponse body = response.getBody();
            if (body.getErrcode() == 40001) {
                // invalid credential, access_token is invalid or not latest
                access_token = getAccessToken();
                return media_check_async(openId, image_url, scene);
            } else if (body.getErrcode() != 0) {
                body.setErrmsg("含违规信息");
            }
            return body;
        }
        return MediaCheckAsyncResponse.BuildError();
    }

    /**
     * 检查个人头像
     *
     * @param openId
     * @param image_url
     * @return
     */
    public MediaCheckAsyncResponse check_image_user_info(String openId, String image_url) {
        return media_check_async(openId, image_url, 1);
    }

    /**
     * 评论图片
     *
     * @param openId
     * @param image_url
     * @return
     */
    public MediaCheckAsyncResponse check_image_user_comment(String openId, String image_url) {
        return media_check_async(openId, image_url, 2);
    }

    /**
     * 论坛 发布内容 图片
     */
    public MediaCheckAsyncResponse check_image_forum(String openId, String image_url) {
        return media_check_async(openId, image_url, 3);
    }
}
